//
// Portions of this code are from OpenBlt, by Brian Swetland
//

#include <types.h>
#include "mem.h"

#include "memory.h"

extern uint32 *KernelPageTable;


static unsigned char size_map[1025] = {
    KM16,
    
    KM16, KM16, KM16, KM16, KM16, KM16, KM16, KM16,
    KM16, KM16, KM16, KM16, KM16, KM16, KM16, KM16,

    KM32, KM32, KM32, KM32, KM32, KM32, KM32, KM32,
    KM32, KM32, KM32, KM32, KM32, KM32, KM32, KM32,

    KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64,
    KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64,
    KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64,
    KM64, KM64, KM64, KM64, KM64, KM64, KM64, KM64,

    KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
    KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
    KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
    KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
    KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
    KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
    KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
    KM128, KM128, KM128, KM128, KM128, KM128, KM128, KM128,
    
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,    
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,
    KM256, KM256, KM256, KM256, KM256, KM256, KM256, KM256,

    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,    
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,    
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,
    KM512, KM512, KM512, KM512, KM512, KM512, KM512, KM512,

    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,    
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,    
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,    
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,    
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024,
    KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024, KM1024    
};


void *kmallocB(int size)
{
    if(size < 1025){
        return kmalloc(size_map[size /* X? -1 */] );        
    } else {
        KePanic("illegal size in kmallocB");        
    }
    return NULL; /* for paranoid compilers */
}

void kfreeB(int size, void *block)
{
    if(size < 1025){
        kfree(size_map[size /* X? -1 */],block);        
    } else {
        KePanic("illegal size in kmallocB");        
    }
}



struct km_mnode 
{
    struct km_mnode *next;    
};

static struct _km_map
{
    int size;
    int used_count;
    int fresh_count;
    int free_count;
    struct km_mnode *free_chain;
    void *fresh_chain;    
} km_map[7] = {
    {   16,   0, 256, 0, NULL, NULL },
    {   32,   0, 128, 0, NULL, NULL },
    {   64,   0,  64, 0, NULL, NULL },
    {  128,   0,  32, 0, NULL, NULL },
    {  256,   0,  16, 0, NULL, NULL },
    {  512,   0,   8, 0, NULL, NULL },
    { 1024,   0,   4, 0, NULL, NULL }
};        

void memory_status(void)
{
    int i;    
    kprintf("\nsize.... used.... free.... fresh...\n");    
    for(i=0;i<7;i++){
        kprintf("%x %x %x %x\n", km_map[i].size, km_map[i].used_count,
                km_map[i].free_count, km_map[i].fresh_count);
    }
}

void memory_init(void) 
{
    int i;

    for(i=0;i<7;i++)
        km_map[i].fresh_chain = MmAllocPages((aspace *)KernelPageTable, 1, 3, NULL);
}


void *kmalloc(int size)
{
    struct _km_map *km;    
    void *block;    
    if(size > KM1024) KePanic("illegal size in kmalloc()");
    km = &km_map[size];

    km->used_count++;

    if(km->free_chain) {
            /* recycle free'd blocks if available */
        km->free_count--;
        block = (void *) km->free_chain;
        km->free_chain = km->free_chain->next;
    } else {
            /* shave a new block off of the fresh page if
               we can't recycle */
        km->fresh_count--;
        block = km->fresh_chain;

        if(km->fresh_count){
                /* still some left, just bump us to the next chunk */
            km->fresh_chain = (void *)
                (((char *) km->fresh_chain) + km->size);        
        } else {
                /* gotta grab a new page */
            km->fresh_count = 4096 / km->size;        
            km->fresh_chain = MmAllocPages((aspace *)KernelPageTable, 1,3, NULL);            
        }
    }
    
    return block;    
}

void kfree(int size, void *block)
{
    struct _km_map *km;    
    if(size > KM1024) KePanic("illegal size in kmalloc()");
    km = &km_map[size];
    
    km->free_count++;    
    km->used_count--;
    ((struct km_mnode *) block)->next = km->free_chain;    
    km->free_chain = (struct km_mnode *) block;    
}

